package pixelradar.map;

import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.resources.I18n;
import pixelradar.Mw;
import pixelradar.api.IMwChunkOverlay;
import pixelradar.api.IMwDataProvider;
import pixelradar.api.MwAPI;
import pixelradar.config.Config;
import pixelradar.config.MapModeConfig;
import pixelradar.config.PokeradarConfig;
import pixelradar.entities.EntityFinder;
import pixelradar.map.mapmode.MapMode;
import pixelradar.util.Reference;
import pixelradar.util.Render;

import java.awt.*;
import java.awt.geom.Point2D.Double;
import java.util.ArrayList;

public class MapRenderer {
    public Double playerArrowScreenPos = new Double(0.0D, 0.0D);
    protected Mw mw;
    private final MapMode mapMode;
    private final MapView mapView;
    private int textOffset = 12;
    private int textY = 0;
    private int textX = 0;

    public MapRenderer(Mw mw, MapMode mapMode, MapView mapView) {
        this.mw = mw;
        this.mapMode = mapMode;
        this.mapView = mapView;
    }

    private static void paintChunk(MapMode mapMode, MapView mapView, IMwChunkOverlay overlay) {
        int chunkX = overlay.getCoordinates().x;
        int chunkZ = overlay.getCoordinates().y;
        float filling = overlay.getFilling();
        Double topCorner = mapMode.blockXZtoScreenXY(mapView, chunkX << 4, chunkZ << 4);
        Double botCorner = mapMode.blockXZtoScreenXY(mapView, chunkX + 1 << 4, chunkZ + 1 << 4);
        calCornerCoords(mapMode, topCorner);
        calCornerCoords(mapMode, botCorner);
        double sizeX = (botCorner.x - topCorner.x) * (double) filling;
        double sizeY = (botCorner.y - topCorner.y) * (double) filling;
        double offsetX = (botCorner.x - topCorner.x - sizeX) / 2.0D;
        double offsetY = (botCorner.y - topCorner.y - sizeY) / 2.0D;
        if (overlay.hasBorder()) {
            Render.setColour(overlay.getBorderColor());
            Render.drawRectBorder(topCorner.x + 1.0D, topCorner.y + 1.0D, botCorner.x - topCorner.x - 1.0D, botCorner.y - topCorner.y - 1.0D, overlay.getBorderWidth());
        }

        Render.setColour(overlay.getColor());
        Render.drawRect(topCorner.x + offsetX + 1.0D, topCorner.y + offsetY + 1.0D, sizeX - 1.0D, sizeY - 1.0D);
    }

    private static void calCornerCoords(MapMode mapMode, Double corner) {
        corner.x = Math.max(mapMode.getX(), corner.x);
        corner.x = Math.min(mapMode.getX() + mapMode.getW(), corner.x);
        corner.y = Math.max(mapMode.getY(), corner.y);
        corner.y = Math.min(mapMode.getY() + mapMode.getH(), corner.y);
    }

    private void drawMap() {
        int regionZoomLevel = Math.max(0, this.mapView.getZoomLevel());
        double tSize = this.mw.textureSize;
        double zoomScale = 1 << regionZoomLevel;
        double u;
        double v;
        double w;
        double h;
        if (!this.mapMode.getConfig().circular && Config.mapPixelSnapEnabled && this.mapView.getZoomLevel() >= 0) {
            u = (double) Math.round(this.mapView.getMinX() / zoomScale) / tSize % 1.0D;
            v = (double) Math.round(this.mapView.getMinZ() / zoomScale) / tSize % 1.0D;
            w = (double) Math.round(this.mapView.getWidth() / zoomScale) / tSize;
            h = (double) Math.round(this.mapView.getHeight() / zoomScale) / tSize;
        } else {
            double tSizeInBlocks = tSize * zoomScale;
            u = this.mapView.getMinX() / tSizeInBlocks % 1.0D;
            v = this.mapView.getMinZ() / tSizeInBlocks % 1.0D;
            w = this.mapView.getWidth() / tSizeInBlocks;
            h = this.mapView.getHeight() / tSizeInBlocks;
        }

        GlStateManager.pushMatrix();
        if (this.mapMode.getConfig().rotate && this.mapMode.getConfig().circular) {
            GlStateManager.rotate(this.mw.mapRotationDegrees, 0.0F, 0.0F, 1.0F);
        }

        if (this.mapMode.getConfig().circular) {
            Render.setCircularStencil(0.0D, 0.0D, (double) this.mapMode.getH() / 2.0D);
        }

        if (this.mapView.getUndergroundMode() && regionZoomLevel == 0) {
            this.mw.undergroundMapTexture.requestView(this.mapView);
            Render.setColourWithAlphaPercent(0, this.mapMode.getConfig().alphaPercent);
            Render.drawRect(this.mapMode.getX(), this.mapMode.getY(), this.mapMode.getW(), this.mapMode.getH());
            Render.setColourWithAlphaPercent(16777215, this.mapMode.getConfig().alphaPercent);
            this.mw.undergroundMapTexture.bind();
            Render.drawTexturedRect(this.mapMode.getX(), this.mapMode.getY(), this.mapMode.getW(), this.mapMode.getH(), u, v, u + w, v + h);
        } else {
            MapViewRequest req = new MapViewRequest(this.mapView);
            this.mw.mapTexture.requestView(req, this.mw.executor, this.mw.regionManager);
            this.drawBackground(tSize, u, v, w, h);
            if (this.mw.mapTexture.isLoaded(req)) {
                this.mw.mapTexture.bind();
                Render.setColourWithAlphaPercent(16777215, this.mapMode.getConfig().alphaPercent);
                Render.drawTexturedRect(this.mapMode.getX(), this.mapMode.getY(), this.mapMode.getW(), this.mapMode.getH(), u, v, u + w, v + h);
            }
        }

        IMwDataProvider provider = this.drawOverlay();
        if (provider != null) {
            GlStateManager.pushMatrix();
            provider.onDraw(this.mapView, this.mapMode);
            GlStateManager.popMatrix();
        }

        if (this.mapMode.getConfig().circular) {
            Render.disableStencil();
        }

        GlStateManager.popMatrix();
    }

    private void drawBackground(double tSize, double u, double v, double w, double h) {
        if (!Config.backgroundTextureMode.equals(Config.backgroundModeStringArray[0])) {
            double bu1 = 0.0D;
            double bu2 = 1.0D;
            double bv1 = 0.0D;
            double bv2 = 1.0D;
            if (Config.backgroundTextureMode.equals(Config.backgroundModeStringArray[2])) {
                double bSize = tSize / 256.0D;
                bu1 = u * bSize;
                bu2 = (u + w) * bSize;
                bv1 = v * bSize;
                bv2 = (v + h) * bSize;
            }

            this.mw.mc.renderEngine.bindTexture(Reference.backgroundTexture);
            Render.setColourWithAlphaPercent(16777215, this.mapMode.getConfig().alphaPercent);
            Render.drawTexturedRect(this.mapMode.getX(), this.mapMode.getY(), this.mapMode.getW(), this.mapMode.getH(), bu1, bv1, bu2, bv2);
        } else {
            Render.setColourWithAlphaPercent(0, this.mapMode.getConfig().alphaPercent);
            Render.drawRect(this.mapMode.getX(), this.mapMode.getY(), this.mapMode.getW(), this.mapMode.getH());
        }

    }

    private void drawBorder() {
        if (this.mapMode.getConfig().circular) {
            this.mw.mc.renderEngine.bindTexture(Reference.roundMapTexture);
        } else {
            this.mw.mc.renderEngine.bindTexture(Reference.squareMapTexture);
        }

        Render.setColour(-1);
        Render.drawTexturedRect((double) this.mapMode.getX() / 0.75D, (double) this.mapMode.getY() / 0.75D, (double) this.mapMode.getW() / 0.75D, (double) this.mapMode.getH() / 0.75D, 0.0D, 0.0D, 1.0D, 1.0D);
    }

    public void drawEntityArrow(double x, double z, double r, boolean isPlayer) {
        double scale = this.mapView.getDimensionScaling(this.mapView.getDimension());
        Double p = this.mapMode.getClampedScreenXY(this.mapView, x * scale, z * scale);
        if (isPlayer) {
            Render.setColour(-16777216);
            Render.drawArrow(p.x, p.y, r, 6.5D);
            Render.setColour(-16776961);
        } else {
            Render.setColour(Color.BLACK.getRGB());
            Render.drawArrow(p.x, p.y, r, 6.5D);
            Render.setColour(Color.LIGHT_GRAY.getRGB());
        }

        Render.drawArrow(p.x, p.y, r, 5.0D);
    }

    private void drawPlayerArrow() {
        GlStateManager.pushMatrix();
        double scale = this.mapView.getDimensionScaling(this.mw.playerDimension);
        Double p = this.mapMode.getClampedScreenXY(this.mapView, this.mw.playerX * scale, this.mw.playerZ * scale);
        this.playerArrowScreenPos.setLocation(p.x + (double) this.mapMode.getXTranslation(), p.y + (double) this.mapMode.getYTranslation());
        GlStateManager.translate(p.x, p.y, 0.0D);
        if (!this.mapMode.getConfig().rotate || !this.mapMode.getConfig().circular) {
            GlStateManager.rotate(-this.mw.mapRotationDegrees, 0.0F, 0.0F, 1.0F);
        }

        double arrowSize = this.mapMode.getConfig().playerArrowSize;
        Render.setColour(-1);
        this.mw.mc.renderEngine.bindTexture(Reference.playerArrowTexture);
        Render.drawTexturedRect(-arrowSize, -arrowSize, arrowSize * 2.0D, arrowSize * 2.0D, 0.0D, 0.0D, 1.0D, 1.0D);
        GlStateManager.popMatrix();
        EntityFinder.getAndDraw(this, this.mw.mc);
    }

    private void drawIcons() {
        GlStateManager.pushMatrix();
        if (this.mapMode.getConfig().rotate && this.mapMode.getConfig().circular) {
            GlStateManager.rotate(this.mw.mapRotationDegrees, 0.0F, 0.0F, 1.0F);
        }

        this.mw.markerManager.drawMarkers(this.mapMode, this.mapView);
        this.mw.markerManager.drawPKMarkers(this.mapMode, this.mapView, this, this.mw.mapRotationDegrees);
        if (this.mw.playerTrail.enabled) {
            this.mw.playerTrail.draw(this.mapMode, this.mapView);
        }

        this.drawNorthArrow();
        GlStateManager.popMatrix();
        this.drawPlayerArrow();
    }

    private void drawNorthArrow() {
        if (this.mapMode.getConfig().rotate) {
            double y = (double) this.mapMode.getH() / 2.0D;
            double arrowSize = this.mapMode.getConfig().playerArrowSize;
            Render.setColour(-1);
            this.mw.mc.renderEngine.bindTexture(Reference.northArrowTexture);
            Render.drawTexturedRect(-arrowSize, -y - arrowSize * 2.0D, arrowSize * 2.0D, arrowSize * 2.0D, 0.0D, 0.0D, 1.0D, 1.0D);
        }

    }

    private void drawStatusText() {
        this.textOffset = 12;
        this.textY = this.mapMode.getTextY();
        this.textX = this.mapMode.getTextX();
        this.drawCoords();
        this.drawBiomeName();
        this.drawUndergroundMode();
    }

    private void drawCoords() {
        if (!this.mapMode.getConfig().coordsMode.equals(MapModeConfig.coordsModeStringArray[0])) {
            GlStateManager.pushMatrix();
            GlStateManager.translate((float) this.textX, (float) this.textY, 0.0F);
            if (this.mapMode.getConfig().coordsMode.equals(MapModeConfig.coordsModeStringArray[1])) {
                GlStateManager.scale(0.5F, 0.5F, 1.0F);
                this.textOffset = (int) ((float) this.textOffset * 0.5F);
            }

            Render.drawCentredString(0, 0, this.mapMode.getTextColour(), "%d, %d, %d", this.mw.playerXInt, this.mw.playerYInt, this.mw.playerZInt);
            this.textY += this.textOffset;
            GlStateManager.popMatrix();
        }

    }

    private void drawBiomeName() {
        if (!this.mapMode.getConfig().biomeMode.equals(MapModeConfig.coordsModeStringArray[0])) {
            GlStateManager.pushMatrix();
            GlStateManager.translate((float) this.textX, (float) this.textY, 0.0F);
            if (this.mapMode.getConfig().biomeMode.equals(MapModeConfig.coordsModeStringArray[1])) {
                GlStateManager.scale(0.5F, 0.5F, 1.0F);
                this.textOffset = (int) ((float) this.textOffset * 0.5F);
            }

            Render.drawCentredString(0, 0, this.mapMode.getTextColour(), "".equals(this.mw.playerBiome) ? "BiomeName" : this.mw.playerBiome);
            this.textY += this.textOffset;
            GlStateManager.popMatrix();
        }

    }

    private void drawUndergroundMode() {
        if (Config.undergroundMode) {
            GlStateManager.pushMatrix();
            GlStateManager.translate((float) this.textX, (float) this.textY, 0.0F);
            GlStateManager.scale(0.5F, 0.5F, 1.0F);
            this.textOffset = (int) ((float) this.textOffset * 0.5F);
            Render.drawCentredString(0, 0, this.mapMode.getTextColour(), I18n.format("key.mw_underground_mode"));
            this.textY += this.textOffset;
            GlStateManager.popMatrix();
        }

    }

    private IMwDataProvider drawOverlay() {
        IMwDataProvider provider = MwAPI.getCurrentDataProvider();
        if (provider != null) {
            ArrayList<IMwChunkOverlay> overlays = provider.getChunksOverlay(this.mapView.getDimension(), this.mapView.getX(), this.mapView.getZ(), this.mapView.getMinX(), this.mapView.getMinZ(), this.mapView.getMaxX(), this.mapView.getMaxZ());
            if (overlays != null) {

                for (IMwChunkOverlay overlay : overlays) {
                    paintChunk(this.mapMode, this.mapView, overlay);
                }
            }
        }

        return provider;
    }

    public void draw() {
        this.mapMode.updateMargin();
        this.mapMode.setScreenRes();
        this.mapView.setMapWH(this.mapMode);
        this.mapView.setTextureSize(this.mw.textureSize);
        if (PokeradarConfig.enableMap) {
            GlStateManager.pushMatrix();
            GlStateManager.translate(this.mapMode.getXTranslation(), this.mapMode.getYTranslation(), 0.0D);
            this.drawMap();
            if (this.mapMode.getConfig().borderMode) {
                this.drawBorder();
            }

            this.drawIcons();
            this.drawStatusText();
            GlStateManager.enableDepth();
            GlStateManager.popMatrix();
        }

        EntityFinder.getAndDraw(this, this.mw.mc);
    }

    public void drawDummy() {
        this.mapMode.updateMargin();
        this.mapMode.setScreenRes();
        GlStateManager.pushMatrix();
        GlStateManager.translate(this.mapMode.getXTranslation(), this.mapMode.getYTranslation(), 1000.0D);
        double u = 0.0D;
        double v = 0.0D;
        double w;
        double h;
        if (!this.mapMode.getConfig().circular) {
            w = this.mapMode.getConfig().widthPercent / 100.0D;
            h = this.mapMode.getConfig().heightPercent / 100.0D;
        } else {
            double scale1 = this.mw.mc.displayWidth < this.mw.mc.displayHeight ? 1.0D : (double) this.mw.mc.displayHeight / (double) this.mw.mc.displayWidth;
            double scale2 = this.mw.mc.displayWidth < this.mw.mc.displayHeight ? (double) this.mw.mc.displayWidth / (double) this.mw.mc.displayHeight : 1.0D;
            w = this.mapMode.getConfig().widthPercent / 100.0D * scale1;
            h = this.mapMode.getConfig().heightPercent / 100.0D * scale2;
        }

        GlStateManager.pushMatrix();
        if (this.mapMode.getConfig().rotate && this.mapMode.getConfig().circular) {
            GlStateManager.rotate(0.0F, 0.0F, 0.0F, 1.0F);
        }

        if (this.mapMode.getConfig().circular) {
            Render.setCircularStencil(0.0D, 0.0D, (double) this.mapMode.getH() / 2.0D);
        }

        this.mw.mc.renderEngine.bindTexture(Reference.DummyMapTexture);
        Render.setColourWithAlphaPercent(16777215, 60);
        Render.drawTexturedRect(this.mapMode.getX(), this.mapMode.getY(), this.mapMode.getW(), this.mapMode.getH(), u, v, u + w, v + h);
        if (this.mapMode.getConfig().circular) {
            Render.disableStencil();
        }

        GlStateManager.popMatrix();
        if (this.mapMode.getConfig().borderMode) {
            this.drawBorder();
        }

        GlStateManager.pushMatrix();
        if (this.mapMode.getConfig().rotate && this.mapMode.getConfig().circular) {
            GlStateManager.rotate(0.0F, 0.0F, 0.0F, 1.0F);
        }

        if (this.mapMode.getConfig().rotate) {
            this.drawNorthArrow();
        }

        GlStateManager.popMatrix();
        this.drawStatusText();
        GlStateManager.enableDepth();
        GlStateManager.popMatrix();
    }

    public MapMode getMapMode() {
        return this.mapMode;
    }

    public MapView getMapView() {
        return this.mapView;
    }
}
